// Decompiled on 周六 2月 22 19:31:49 CST 2025 with Zomboid Decompiler v0.1.3 using Vineflower.
package zombie.core.textures;

import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.zip.CRC32;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;
import zombie.core.utils.BooleanGrid;

public final class PNGDecoder {
    private static final byte[] SIGNATURE = new byte[]{-119, 80, 78, 71, 13, 10, 26, 10};
    private static final int IHDR = 1229472850;
    private static final int PLTE = 1347179589;
    private static final int tRNS = 1951551059;
    private static final int IDAT = 1229209940;
    private static final int IEND = 1229278788;
    private static final byte COLOR_GREYSCALE = 0;
    private static final byte COLOR_TRUECOLOR = 2;
    private static final byte COLOR_INDEXED = 3;
    private static final byte COLOR_GREYALPHA = 4;
    private static final byte COLOR_TRUEALPHA = 6;
    private final InputStream input;
    private final CRC32 crc;
    private final byte[] buffer;
    private int chunkLength;
    private int chunkType;
    private int chunkRemaining;
    private int width;
    private int height;
    private int bitdepth;
    private int colorType;
    private int bytesPerPixel;
    private byte[] palette;
    private byte[] paletteA;
    private byte[] transPixel;
    int maskM = 0;
    public int maskID = 0;
    public BooleanGrid mask;
    public boolean bDoMask = false;
    public long readTotal = 0L;

    public PNGDecoder(InputStream _input, boolean _bDoMask) throws IOException {
        this.input = _input;
        this.crc = new CRC32();
        this.buffer = new byte[4096];
        this.bDoMask = _bDoMask;
        this.readFully(this.buffer, 0, SIGNATURE.length);
        if (!checkSignature(this.buffer)) {
            throw new IOException("Not a valid PNG file");
        } else {
            this.openChunk(1229472850);
            this.readIHDR();
            this.closeChunk();

            while (true) {
                this.openChunk();
                switch (this.chunkType) {
                    case 1229209940:
                        if (this.colorType == 3 && this.palette == null) {
                            throw new IOException("Missing PLTE chunk");
                        }

                        if (_bDoMask) {
                            this.mask = new BooleanGrid(this.width, this.height);
                        }

                        return;
                    case 1347179589:
                        this.readPLTE();
                        break;
                    case 1951551059:
                        this.readtRNS();
                }

                this.closeChunk();
            }
        }
    }

    public int getHeight() {
        return this.height;
    }

    public int getWidth() {
        return this.width;
    }

    public boolean hasAlphaChannel() {
        return this.colorType == 6 || this.colorType == 4;
    }

    public boolean hasAlpha() {
        return this.hasAlphaChannel() || this.paletteA != null || this.transPixel != null;
    }

    public boolean isRGB() {
        return this.colorType == 6 || this.colorType == 2 || this.colorType == 3;
    }

    public void overwriteTRNS(byte r, byte g, byte b) {
        if (this.hasAlphaChannel()) {
            throw new UnsupportedOperationException("image has an alpha channel");
        } else {
            byte[] byte0 = this.palette;
            if (byte0 == null) {
                this.transPixel = new byte[]{0, r, 0, g, 0, b};
            } else {
                this.paletteA = new byte[byte0.length / 3];
                byte byte1 = 0;

                for (int _int = 0; byte1 < byte0.length; _int++) {
                    if (byte0[byte1] != r || byte0[byte1 + 1] != g || byte0[byte1 + 2] != b) {
                        this.paletteA[_int] = -1;
                    }

                    byte1 += 3;
                }
            }
        }
    }

    public PNGDecoder.Format decideTextureFormat(PNGDecoder.Format fmt) {
        switch (this.colorType) {
            case 0:
                switch (fmt) {
                    case LUMINANCE:
                    case ALPHA:
                        return fmt;
                    default:
                        return PNGDecoder.Format.LUMINANCE;
                }
            case 1:
            case 5:
            default:
                throw new UnsupportedOperationException("Not yet implemented");
            case 2:
                switch (fmt) {
                    case ABGR:
                    case RGBA:
                    case BGRA:
                    case RGB:
                        return fmt;
                    default:
                        return PNGDecoder.Format.RGB;
                }
            case 3:
                switch (fmt) {
                    case ABGR:
                    case RGBA:
                    case BGRA:
                        return fmt;
                    default:
                        return PNGDecoder.Format.RGBA;
                }
            case 4:
                return PNGDecoder.Format.LUMINANCE_ALPHA;
            case 6:
                switch (fmt) {
                    case ABGR:
                    case RGBA:
                    case BGRA:
                    case RGB:
                        return fmt;
                    default:
                        return PNGDecoder.Format.RGBA;
                }
        }
    }

    public void decode(ByteBuffer _buffer, int stride, PNGDecoder.Format fmt) throws IOException {
        int int0 = _buffer.position();
        int int1 = (this.width * this.bitdepth + 7) / 8 * this.bytesPerPixel;
        byte[] byte0 = new byte[int1 + 1];
        byte[] byte1 = new byte[int1 + 1];
        byte[] byte2 = this.bitdepth < 8 ? new byte[this.width + 1] : null;
        this.maskM = 0;
        Inflater inflater = new Inflater();

        try {
            for (int int2 = 0; int2 < this.height; int2++) {
                this.readChunkUnzip(inflater, byte0, 0, byte0.length);
                this.unfilter(byte0, byte1);
                _buffer.position(int0 + int2 * stride);
                label81:
                switch (this.colorType) {
                    case 0:
                        switch (fmt) {
                            case RGBA:
                                this.copyGREYtoRGBA(_buffer, byte0);
                                break label81;
                            case BGRA:
                            case RGB:
                            default:
                                throw new UnsupportedOperationException("Unsupported format for this image");
                            case LUMINANCE:
                            case ALPHA:
                                this.copy(_buffer, byte0);
                                break label81;
                        }
                    case 1:
                    case 5:
                    default:
                        throw new UnsupportedOperationException("Not yet implemented");
                    case 2:
                        switch (fmt) {
                            case ABGR:
                                this.copyRGBtoABGR(_buffer, byte0);
                                break label81;
                            case RGBA:
                                this.copyRGBtoRGBA(_buffer, byte0);
                                break label81;
                            case BGRA:
                                this.copyRGBtoBGRA(_buffer, byte0);
                                break label81;
                            case RGB:
                                this.copy(_buffer, byte0);
                                break label81;
                            default:
                                throw new UnsupportedOperationException("Unsupported format for this image");
                        }
                    case 3:
                        switch (this.bitdepth) {
                            case 1:
                                this.expand1(byte0, byte2);
                                break;
                            case 2:
                                this.expand2(byte0, byte2);
                                break;
                            case 3:
                            case 5:
                            case 6:
                            case 7:
                            default:
                                throw new UnsupportedOperationException("Unsupported bitdepth for this image");
                            case 4:
                                this.expand4(byte0, byte2);
                                break;
                            case 8:
                                byte2 = byte0;
                        }

                        switch (fmt) {
                            case ABGR:
                                this.copyPALtoABGR(_buffer, byte2);
                                break label81;
                            case RGBA:
                                this.copyPALtoRGBA(_buffer, byte2);
                                break label81;
                            case BGRA:
                                this.copyPALtoBGRA(_buffer, byte2);
                                break label81;
                            default:
                                throw new UnsupportedOperationException("Unsupported format for this image");
                        }
                    case 4:
                        switch (fmt) {
                            case RGBA:
                                this.copyGREYALPHAtoRGBA(_buffer, byte0);
                                break label81;
                            case LUMINANCE_ALPHA:
                                this.copy(_buffer, byte0);
                                break label81;
                            default:
                                throw new UnsupportedOperationException("Unsupported format for this image");
                        }
                    case 6:
                        switch (fmt) {
                            case ABGR:
                                this.copyRGBAtoABGR(_buffer, byte0);
                                break;
                            case RGBA:
                                this.copy(_buffer, byte0);
                                break;
                            case BGRA:
                                this.copyRGBAtoBGRA(_buffer, byte0);
                                break;
                            case RGB:
                                this.copyRGBAtoRGB(_buffer, byte0);
                                break;
                            default:
                                throw new UnsupportedOperationException("Unsupported format for this image");
                        }
                }

                byte[] byte3 = byte0;
                byte0 = byte1;
                byte1 = byte3;
            }
        } finally {
            inflater.end();
        }
    }

    public void decodeFlipped(ByteBuffer _buffer, int stride, PNGDecoder.Format fmt) throws IOException {
        if (stride <= 0) {
            throw new IllegalArgumentException("stride");
        } else {
            int int0 = _buffer.position();
            int int1 = (this.height - 1) * stride;
            _buffer.position(int0 + int1);
            this.decode(_buffer, -stride, fmt);
            _buffer.position(_buffer.position() + int1);
        }
    }

    private void copy(ByteBuffer byteBuffer, byte[] byte1) {
        if (this.bDoMask) {
            byte byte0 = 1;

            for (int _int = byte1.length; byte0 < _int; byte0 += 4) {
                if (byte1[byte0 + 3] % 255 != 0) {
                    this.mask.setValue(this.maskM % this.width, this.maskM / this.width, true);
                }

                this.maskM++;
            }
        }

        byteBuffer.put(byte1, 1, byte1.length - 1);
    }

    private void copyRGBtoABGR(ByteBuffer byteBuffer, byte[] byte4) {
        if (this.transPixel != null) {
            byte byte0 = this.transPixel[1];
            byte byte1 = this.transPixel[3];
            byte byte2 = this.transPixel[5];
            byte byte3 = 1;

            for (int int0 = byte4.length; byte3 < int0; byte3 += 3) {
                byte byte5 = byte4[byte3];
                byte byte6 = byte4[byte3 + 1];
                byte byte7 = byte4[byte3 + 2];
                byte byte8 = -1;
                if (byte5 == byte0 && byte6 == byte1 && byte7 == byte2) {
                    byte8 = 0;
                }

                byteBuffer.put(byte8).put(byte7).put(byte6).put(byte5);
            }
        } else {
            byte byte9 = 1;

            for (int int1 = byte4.length; byte9 < int1; byte9 += 3) {
                byteBuffer.put((byte)-1).put(byte4[byte9 + 2]).put(byte4[byte9 + 1]).put(byte4[byte9]);
            }
        }
    }

    private void copyRGBtoRGBA(ByteBuffer byteBuffer, byte[] byte4) {
        if (this.transPixel != null) {
            byte byte0 = this.transPixel[1];
            byte byte1 = this.transPixel[3];
            byte byte2 = this.transPixel[5];
            byte byte3 = 1;

            for (int int0 = byte4.length; byte3 < int0; byte3 += 3) {
                byte byte5 = byte4[byte3];
                byte byte6 = byte4[byte3 + 1];
                byte byte7 = byte4[byte3 + 2];
                byte byte8 = -1;
                if (byte5 == byte0 && byte6 == byte1 && byte7 == byte2) {
                    byte8 = 0;
                }

                if (this.bDoMask && byte8 == 0) {
                    this.mask.setValue(this.maskID % this.width, this.maskID / this.width, true);
                    this.maskID++;
                }

                byteBuffer.put(byte5).put(byte6).put(byte7).put(byte8);
            }
        } else {
            byte byte9 = 1;

            for (int int1 = byte4.length; byte9 < int1; byte9 += 3) {
                byteBuffer.put(byte4[byte9]).put(byte4[byte9 + 1]).put(byte4[byte9 + 2]).put((byte)-1);
            }
        }
    }

    private void copyRGBtoBGRA(ByteBuffer byteBuffer, byte[] byte4) {
        if (this.transPixel != null) {
            byte byte0 = this.transPixel[1];
            byte byte1 = this.transPixel[3];
            byte byte2 = this.transPixel[5];
            byte byte3 = 1;

            for (int int0 = byte4.length; byte3 < int0; byte3 += 3) {
                byte byte5 = byte4[byte3];
                byte byte6 = byte4[byte3 + 1];
                byte byte7 = byte4[byte3 + 2];
                byte byte8 = -1;
                if (byte5 == byte0 && byte6 == byte1 && byte7 == byte2) {
                    byte8 = 0;
                }

                byteBuffer.put(byte7).put(byte6).put(byte5).put(byte8);
            }
        } else {
            byte byte9 = 1;

            for (int int1 = byte4.length; byte9 < int1; byte9 += 3) {
                byteBuffer.put(byte4[byte9 + 2]).put(byte4[byte9 + 1]).put(byte4[byte9]).put((byte)-1);
            }
        }
    }

    private void copyRGBAtoABGR(ByteBuffer byteBuffer, byte[] byte1) {
        byte byte0 = 1;

        for (int _int = byte1.length; byte0 < _int; byte0 += 4) {
            byteBuffer.put(byte1[byte0 + 3]).put(byte1[byte0 + 2]).put(byte1[byte0 + 1]).put(byte1[byte0]);
        }
    }

    private void copyRGBAtoBGRA(ByteBuffer byteBuffer, byte[] byte1) {
        byte byte0 = 1;

        for (int _int = byte1.length; byte0 < _int; byte0 += 4) {
            byteBuffer.put(byte1[byte0 + 2]).put(byte1[byte0 + 1]).put(byte1[byte0]).put(byte1[byte0 + 3]);
        }
    }

    private void copyRGBAtoRGB(ByteBuffer byteBuffer, byte[] byte1) {
        byte byte0 = 1;

        for (int _int = byte1.length; byte0 < _int; byte0 += 4) {
            byteBuffer.put(byte1[byte0]).put(byte1[byte0 + 1]).put(byte1[byte0 + 2]);
        }
    }

    private void copyPALtoABGR(ByteBuffer byteBuffer, byte[] byte0) {
        if (this.paletteA != null) {
            int int0 = 1;

            for (int int1 = byte0.length; int0 < int1; int0++) {
                int int2 = byte0[int0] & 255;
                byte byte1 = this.palette[int2 * 3 + 0];
                byte byte2 = this.palette[int2 * 3 + 1];
                byte byte3 = this.palette[int2 * 3 + 2];
                byte byte4 = this.paletteA[int2];
                byteBuffer.put(byte4).put(byte3).put(byte2).put(byte1);
            }
        } else {
            int int3 = 1;

            for (int int4 = byte0.length; int3 < int4; int3++) {
                int int5 = byte0[int3] & 255;
                byte byte5 = this.palette[int5 * 3 + 0];
                byte byte6 = this.palette[int5 * 3 + 1];
                byte byte7 = this.palette[int5 * 3 + 2];
                byte byte8 = -1;
                byteBuffer.put(byte8).put(byte7).put(byte6).put(byte5);
            }
        }
    }

    private void copyPALtoRGBA(ByteBuffer byteBuffer, byte[] byte0) {
        if (this.paletteA != null) {
            int int0 = 1;

            for (int int1 = byte0.length; int0 < int1; int0++) {
                int int2 = byte0[int0] & 255;
                byte byte1 = this.palette[int2 * 3 + 0];
                byte byte2 = this.palette[int2 * 3 + 1];
                byte byte3 = this.palette[int2 * 3 + 2];
                byte byte4 = this.paletteA[int2];
                byteBuffer.put(byte1).put(byte2).put(byte3).put(byte4);
            }
        } else {
            int int3 = 1;

            for (int int4 = byte0.length; int3 < int4; int3++) {
                int int5 = byte0[int3] & 255;
                byte byte5 = this.palette[int5 * 3 + 0];
                byte byte6 = this.palette[int5 * 3 + 1];
                byte byte7 = this.palette[int5 * 3 + 2];
                byte byte8 = -1;
                byteBuffer.put(byte5).put(byte6).put(byte7).put(byte8);
            }
        }
    }

    private void copyPALtoBGRA(ByteBuffer byteBuffer, byte[] byte0) {
        if (this.paletteA != null) {
            int int0 = 1;

            for (int int1 = byte0.length; int0 < int1; int0++) {
                int int2 = byte0[int0] & 255;
                byte byte1 = this.palette[int2 * 3 + 0];
                byte byte2 = this.palette[int2 * 3 + 1];
                byte byte3 = this.palette[int2 * 3 + 2];
                byte byte4 = this.paletteA[int2];
                byteBuffer.put(byte3).put(byte2).put(byte1).put(byte4);
            }
        } else {
            int int3 = 1;

            for (int int4 = byte0.length; int3 < int4; int3++) {
                int int5 = byte0[int3] & 255;
                byte byte5 = this.palette[int5 * 3 + 0];
                byte byte6 = this.palette[int5 * 3 + 1];
                byte byte7 = this.palette[int5 * 3 + 2];
                byte byte8 = -1;
                byteBuffer.put(byte7).put(byte6).put(byte5).put(byte8);
            }
        }
    }

    private void copyGREYtoRGBA(ByteBuffer byteBuffer, byte[] byte0) {
        int int0 = 1;

        for (int int1 = byte0.length; int0 < int1; int0++) {
            byte byte1 = byte0[int0];
            byte byte2 = -1;
            byteBuffer.put(byte1).put(byte1).put(byte1).put(byte2);
        }
    }

    private void copyGREYALPHAtoRGBA(ByteBuffer byteBuffer, byte[] byte1) {
        byte byte0 = 1;

        for (int _int = byte1.length; byte0 < _int; byte0 += 2) {
            byte byte2 = byte1[byte0];
            byte byte3 = byte1[byte0 + 1];
            byteBuffer.put(byte2).put(byte2).put(byte2).put(byte3);
        }
    }

    private void expand4(byte[] byte2, byte[] byte1) {
        byte byte0 = 1;

        for (int int0 = byte1.length; byte0 < int0; byte0 += 2) {
            int int1 = byte2[1 + (byte0 >> 1)] & 255;
            switch (int0 - byte0) {
                default:
                    byte1[byte0 + 1] = (byte)(int1 & 15);
                case 1:
                    byte1[byte0] = (byte)(int1 >> 4);
            }
        }
    }

    private void expand2(byte[] byte2, byte[] byte1) {
        byte byte0 = 1;

        for (int int0 = byte1.length; byte0 < int0; byte0 += 4) {
            int int1 = byte2[1 + (byte0 >> 2)] & 255;
            switch (int0 - byte0) {
                default:
                    byte1[byte0 + 3] = (byte)(int1 & 3);
                case 3:
                    byte1[byte0 + 2] = (byte)(int1 >> 2 & 3);
                case 2:
                    byte1[byte0 + 1] = (byte)(int1 >> 4 & 3);
                case 1:
                    byte1[byte0] = (byte)(int1 >> 6);
            }
        }
    }

    private void expand1(byte[] byte2, byte[] byte1) {
        byte byte0 = 1;

        for (int int0 = byte1.length; byte0 < int0; byte0 += 8) {
            int int1 = byte2[1 + (byte0 >> 3)] & 255;
            switch (int0 - byte0) {
                default:
                    byte1[byte0 + 7] = (byte)(int1 & 1);
                case 7:
                    byte1[byte0 + 6] = (byte)(int1 >> 1 & 1);
                case 6:
                    byte1[byte0 + 5] = (byte)(int1 >> 2 & 1);
                case 5:
                    byte1[byte0 + 4] = (byte)(int1 >> 3 & 1);
                case 4:
                    byte1[byte0 + 3] = (byte)(int1 >> 4 & 1);
                case 3:
                    byte1[byte0 + 2] = (byte)(int1 >> 5 & 1);
                case 2:
                    byte1[byte0 + 1] = (byte)(int1 >> 6 & 1);
                case 1:
                    byte1[byte0] = (byte)(int1 >> 7);
            }
        }
    }

    private void unfilter(byte[] byte0, byte[] byte1) throws IOException {
        switch (byte0[0]) {
            case 0:
                break;
            case 1:
                this.unfilterSub(byte0);
                break;
            case 2:
                this.unfilterUp(byte0, byte1);
                break;
            case 3:
                this.unfilterAverage(byte0, byte1);
                break;
            case 4:
                this.unfilterPaeth(byte0, byte1);
                break;
            default:
                throw new IOException("invalide filter type in scanline: " + byte0[0]);
        }
    }

    private void unfilterSub(byte[] _byte) {
        int int0 = this.bytesPerPixel;
        int int1 = int0 + 1;

        for (int int2 = _byte.length; int1 < int2; int1++) {
            _byte[int1] += _byte[int1 - int0];
        }
    }

    private void unfilterUp(byte[] byte0, byte[] byte1) {
        int int0 = this.bytesPerPixel;
        int int1 = 1;

        for (int int2 = byte0.length; int1 < int2; int1++) {
            byte0[int1] += byte1[int1];
        }
    }

    private void unfilterAverage(byte[] byte1, byte[] byte0) {
        int int0 = this.bytesPerPixel;

        int int1;
        for (int1 = 1; int1 <= int0; int1++) {
            byte1[int1] += (byte)((byte0[int1] & 255) >>> 1);
        }

        for (int int2 = byte1.length; int1 < int2; int1++) {
            byte1[int1] += (byte)((byte0[int1] & 255) + (byte1[int1 - int0] & 255) >>> 1);
        }
    }

    private void unfilterPaeth(byte[] byte1, byte[] byte0) {
        int int0 = this.bytesPerPixel;

        int int1;
        for (int1 = 1; int1 <= int0; int1++) {
            byte1[int1] += byte0[int1];
        }

        for (int int2 = byte1.length; int1 < int2; int1++) {
            int int3 = byte1[int1 - int0] & 255;
            int int4 = byte0[int1] & 255;
            int int5 = byte0[int1 - int0] & 255;
            int int6 = int3 + int4 - int5;
            int int7 = int6 - int3;
            if (int7 < 0) {
                int7 = -int7;
            }

            int int8 = int6 - int4;
            if (int8 < 0) {
                int8 = -int8;
            }

            int int9 = int6 - int5;
            if (int9 < 0) {
                int9 = -int9;
            }

            if (int7 <= int8 && int7 <= int9) {
                int5 = int3;
            } else if (int8 <= int9) {
                int5 = int4;
            }

            byte1[int1] += (byte)int5;
        }
    }

    private void readIHDR() throws IOException {
        this.checkChunkLength(13);
        this.readChunk(this.buffer, 0, 13);
        this.width = this.readInt(this.buffer, 0);
        this.height = this.readInt(this.buffer, 4);
        this.bitdepth = this.buffer[8] & 255;
        this.colorType = this.buffer[9] & 255;
        label43:
        switch (this.colorType) {
            case 0:
                if (this.bitdepth != 8) {
                    throw new IOException("Unsupported bit depth: " + this.bitdepth);
                }

                this.bytesPerPixel = 1;
                break;
            case 1:
            case 5:
            default:
                throw new IOException("unsupported color format: " + this.colorType);
            case 2:
                if (this.bitdepth != 8) {
                    throw new IOException("Unsupported bit depth: " + this.bitdepth);
                }

                this.bytesPerPixel = 3;
                break;
            case 3:
                switch (this.bitdepth) {
                    case 1:
                    case 2:
                    case 4:
                    case 8:
                        this.bytesPerPixel = 1;
                        break label43;
                    case 3:
                    case 5:
                    case 6:
                    case 7:
                    default:
                        throw new IOException("Unsupported bit depth: " + this.bitdepth);
                }
            case 4:
                if (this.bitdepth != 8) {
                    throw new IOException("Unsupported bit depth: " + this.bitdepth);
                }

                this.bytesPerPixel = 2;
                break;
            case 6:
                if (this.bitdepth != 8) {
                    throw new IOException("Unsupported bit depth: " + this.bitdepth);
                }

                this.bytesPerPixel = 4;
        }

        if (this.buffer[10] != 0) {
            throw new IOException("unsupported compression method");
        } else if (this.buffer[11] != 0) {
            throw new IOException("unsupported filtering method");
        } else if (this.buffer[12] != 0) {
            throw new IOException("unsupported interlace method");
        }
    }

    private void readPLTE() throws IOException {
        int _int = this.chunkLength / 3;
        if (_int >= 1 && _int <= 256 && this.chunkLength % 3 == 0) {
            this.palette = new byte[_int * 3];
            this.readChunk(this.palette, 0, this.palette.length);
        } else {
            throw new IOException("PLTE chunk has wrong length");
        }
    }

    private void readtRNS() throws IOException {
        switch (this.colorType) {
            case 0:
                this.checkChunkLength(2);
                this.transPixel = new byte[2];
                this.readChunk(this.transPixel, 0, 2);
            case 1:
            default:
                break;
            case 2:
                this.checkChunkLength(6);
                this.transPixel = new byte[6];
                this.readChunk(this.transPixel, 0, 6);
                break;
            case 3:
                if (this.palette == null) {
                    throw new IOException("tRNS chunk without PLTE chunk");
                }

                this.paletteA = new byte[this.palette.length / 3];
                Arrays.fill(this.paletteA, (byte)-1);
                this.readChunk(this.paletteA, 0, this.paletteA.length);
        }
    }

    private void closeChunk() throws IOException {
        if (this.chunkRemaining > 0) {
            this.skip((long)(this.chunkRemaining + 4));
        } else {
            this.readFully(this.buffer, 0, 4);
            int int0 = this.readInt(this.buffer, 0);
            int int1 = (int)this.crc.getValue();
            if (int1 != int0) {
                throw new IOException("Invalid CRC");
            }
        }

        this.chunkRemaining = 0;
        this.chunkLength = 0;
        this.chunkType = 0;
    }

    private void openChunk() throws IOException {
        this.readFully(this.buffer, 0, 8);
        this.chunkLength = this.readInt(this.buffer, 0);
        this.chunkType = this.readInt(this.buffer, 4);
        this.chunkRemaining = this.chunkLength;
        this.crc.reset();
        this.crc.update(this.buffer, 4, 4);
    }

    private void openChunk(int _int) throws IOException {
        this.openChunk();
        if (this.chunkType != _int) {
            throw new IOException("Expected chunk: " + Integer.toHexString(_int));
        }
    }

    private void checkChunkLength(int _int) throws IOException {
        if (this.chunkLength != _int) {
            throw new IOException("Chunk has wrong size");
        }
    }

    private int readChunk(byte[] _byte, int int1, int int0) throws IOException {
        if (int0 > this.chunkRemaining) {
            int0 = this.chunkRemaining;
        }

        this.readFully(_byte, int1, int0);
        this.crc.update(_byte, int1, int0);
        this.chunkRemaining -= int0;
        return int0;
    }

    private void refillInflater(Inflater inflater) throws IOException {
        while (this.chunkRemaining == 0) {
            this.closeChunk();
            this.openChunk(1229209940);
        }

        int _int = this.readChunk(this.buffer, 0, this.buffer.length);
        inflater.setInput(this.buffer, 0, _int);
    }

    private void readChunkUnzip(Inflater inflater, byte[] _byte, int int1, int int2) throws IOException {
        assert _byte != this.buffer;

        try {
            do {
                int int0 = inflater.inflate(_byte, int1, int2);
                if (int0 <= 0) {
                    if (inflater.finished()) {
                        throw new EOFException();
                    }

                    if (!inflater.needsInput()) {
                        throw new IOException("Can't inflate " + int2 + " bytes");
                    }

                    this.refillInflater(inflater);
                } else {
                    int1 += int0;
                    int2 -= int0;
                }
            } while (int2 > 0);
        } catch (DataFormatException dataFormatException) {
            throw (IOException)new IOException("inflate error").initCause(dataFormatException);
        }
    }

    private void readFully(byte[] _byte, int int1, int int2) throws IOException {
        do {
            int int0 = this.input.read(_byte, int1, int2);
            if (int0 < 0) {
                throw new EOFException();
            }

            int1 += int0;
            int2 -= int0;
            this.readTotal += (long)int0;
        } while (int2 > 0);
    }

    private int readInt(byte[] _byte, int _int) {
        return _byte[_int] << 24 | (_byte[_int + 1] & 0xFF) << 16 | (_byte[_int + 2] & 0xFF) << 8 | _byte[_int + 3] & 0xFF;
    }

    private void skip(long long0) throws IOException {
        while (long0 > 0L) {
            long long1 = this.input.skip(long0);
            if (long1 < 0L) {
                throw new EOFException();
            }

            long0 -= long1;
        }
    }

    private static boolean checkSignature(byte[] _byte) {
        for (int _int = 0; _int < SIGNATURE.length; _int++) {
            if (_byte[_int] != SIGNATURE[_int]) {
                return false;
            }
        }

        return true;
    }

    public static enum Format {
        ALPHA(1, true),
        LUMINANCE(1, false),
        LUMINANCE_ALPHA(2, true),
        RGB(3, false),
        RGBA(4, true),
        BGRA(4, true),
        ABGR(4, true);

        final int numComponents;
        final boolean hasAlpha;

        private Format(int int1, boolean _boolean) {
            this.numComponents = int1;
            this.hasAlpha = _boolean;
        }

        public int getNumComponents() {
            return this.numComponents;
        }

        public boolean isHasAlpha() {
            return this.hasAlpha;
        }
    }
}
